﻿using System;
using Direct.Logging;
using Direct.Adapters.ServiceLocation.UnityServiceLocator;
using Direct.Services;
using Direct.EntityStore;
using Direct.Security;
using Direct.Events;
using Direct.Modularity;
using Direct.Core;
using Direct.Context;
using Direct.Product;
using Direct.ApplicationModel;

namespace Direct.Bootstrap
{
    public class Bootstrapper : IBootstrapper
    {
        #region IBootstrapper Members

        private class BootLoggerFactory : ILoggerFactory
        {
            private ServerBootLoggerAdapter _bootLogger;
            public BootLoggerFactory(ServerBootLoggerAdapter bootLogger)
            {
                _bootLogger = bootLogger;
            }

            public ILogger CreateLogger(string name)
            {
                return _bootLogger;
            }
        }

        public void Run(IBootLogger bootLogger, IPathMapper pathMapper)
        {
            var logger = new ServerBootLoggerAdapter(bootLogger);
            logger.Log("Bootstrapper starting...", Category.Info, Priority.None);
            try
            {
                logger.Log("Creating services container " + typeof(UnityServiceLocator).FullName, Category.Debug, Priority.None);
                var serviceLocator = new UnityServiceLocator(null, logger);

                logger.Log("Setting service locator provider", Category.Debug, Priority.None);

                CurrentServiceProvider.Set(serviceLocator);

                //registrar o ServiceLocator
                ServiceLocator.SetLocatorProvider(() => serviceLocator);

                //registrar o locator
                ServiceLocator.Register<IServiceLocator>(serviceLocator);

                // registrar o path mapper
                ServiceLocator.Register<IPathMapper>(pathMapper);

                // serviços de dados de request e de sessão
                ServiceLocator.Register<IContextDataService>(new ContextDataService());
                ServiceLocator.Register<ISessionDataService>(new SessionDataService());

                // registrar o gerenciador de 'EntityStores'
                ServiceLocator.Register<IEntityStoreManager>(new EntityStoreManager());

                // registrar o factory de logs para o entity store
                ServiceLocator.Register<ILoggerFactory>(new BootLoggerFactory(logger));

                // registrar o gerenciador de log
                ServiceLocator.Register<ILogManager>(new LogManager());

                // registrar o logger do sistema
                ServiceLocator.GetInstance<ILogManager>().RegisterLogger(logger);

                // registrar o servico de gerenciamento de usuarios
                serviceLocator.Register<IAccountService>(new AccountService());

                // serviços de autenticacao e autorização
                ServiceLocator.Register<IAuthenticationService>(new AuthenticationService());
                ServiceLocator.Register<IAuthorizationService>(new AuthorizationService());

                //agregador de eventos
                ServiceLocator.Register<IEventAggregator, EventAggregator>(true);

                // product info
                ServiceLocator.Register<IProductService>(new ProductService());

                // app model
                ServiceLocator.Register<IApplicationModelService>(new ApplicationModelService());

                //registrar os servicos de modulos
                ServiceLocator.Register<IModuleCatalog>(new DirectoryModuleCatalog2(pathMapper.MapPath("~/bin")));
                ServiceLocator.Register<IModuleInitializer, ModuleInitializer>(true);
                ServiceLocator.Register<IModuleManager, ModuleManager>(true);

                logger.Log("Loading modules...", Category.Info, Priority.None);
                //carregar os modulos
                ServiceLocator.GetInstance<IModuleManager>().Run();

                logger.Log("Server started", Category.Info, Priority.None);

                ServiceLocator.GetInstance<ILogManager>()
                    .GetLogger("START_UP")
                    .Log("Server started", Category.Debug, Priority.None);
            }
            catch (Exception ex)
            {
                logger.LogException("Fatal error on server bootstrap", ex, Priority.High);
            }
        }

        #endregion
    }

}
